timeout.js ➔ ... ➔ wrapper.cancel   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
var Future = require('./Future').Future
2
3
/**
4
 * @class
5
 * @param {string} message
6
 */
7
function TimeoutException (message) {
8
  this.message = message || 'Timeout has exceeded'
9
  this.stack = (new Error()).stack
10
}
11
12
var _ = TimeoutException
13
14
_.prototype = Object.create(Error.prototype)
15
_.prototype.name = 'TimeoutException'
16
_.prototype.constructor = _
17
18
function CancellationException (message) {
19
  this.message = message || 'Promise has been cancelled'
20
  this.stack = (new Error()).stack
21
}
22
23
_ = CancellationException
24
_.prototype = Object.create(Error.prototype)
25
_.prototype.name = 'CancellationException'
26
_.prototype.constructor = _
27
28
/**
29
 * @interface ICancellablePromise
30
 * @template T
31
 * @extends Thenable.<T>
32
 */
33
34
/**
35
 * @function ICancellablePromise#cancel
36
 *
37
 * @param {boolean} [silent] Whether to cancel with CancellationException or
38
 * just pretend that nothing has happened
39
 *
40
 * @return ICancellablePromise The very same instance
41
 */
42
43
/**
44
 * @callback timeout~onTimeout
45
 *
46
 * @param {Function} resolve
47
 * @param {Function} reject
48
 * @param {TimeoutException} error
49
 */
50
51
/**
52
 * @param {Promise.<*>|Thenable.<*>} promise Promise to add time bound to
53
 * @param {int} [timeout] Timeout in milliseconds
54
 * @param {timeout~onTimeout|string} [callback] Callback to be run on timeout.
55
 *   If string is passed, it is used as a message in timeout exception.
56
 * @param {string} [message] Error message
57
 * @return {ICancellablePromise.<*>}
58
 */
59
function timeout (promise, timeout, callback, message) {
60
  if (typeof timeout !== 'number' || timeout < 0) {
61
    promise.cancel = function () { return promise }
62
    return promise
63
  }
64
  if (typeof message !== 'string') {
65
    message = typeof callback === 'string' ? callback : 'Timeout of ' + timeout + ' ms has exceeded'
66
  }
67
  if (typeof callback !== 'function') {
68
    callback = function (_, reject, error) {
69
      reject(error)
70
    }
71
  }
72
  var wrapper = Future.wrap(promise)
73
  var bind = setTimeout(function () {
74
    var error = callback.length > 2 ? new TimeoutException(message) : null
75
    callback(wrapper.resolve, wrapper.reject, error)
76
  }, timeout)
77
  var cancel = function (silent) {
78
    clearTimeout(bind)
79
    if (!silent) {
80
      wrapper.reject(new CancellationException())
81
    }
82
  }
83
  wrapper.then(cancel, cancel)
84
  wrapper.cancel = function (silent) {
85
    cancel(silent)
86
    return wrapper
87
  }
88
  return wrapper
89
}
90
91
/**
92
 * Delays processing of callback for specified time. If no callback is
93
 * given, returns empty promise that will resolve in specified time
94
 *
95
 * @param {int} time
96
 * @param {Function} [callback]
97
 *
98
 * @return {Thenable.<*>}
99
 */
100
function delay (time, callback) {
101
  callback = callback || function () {}
102
  var target = new Future()
103
  var resolve = function () {
104
    try {
105
      target.resolve(callback())
106
    } catch (e) {
107
      target.reject(e)
108
    }
109
  }
110
  var bind = setTimeout(resolve, time)
111
  target.cancel = function (silent) {
112
    clearTimeout(bind)
113
    silent ? resolve() : target.reject(new CancellationException())
114
    return target
115
  }
116
  return target
117
}
118
119
/**
120
 * Wraps given promise with another one which won't resolve earlier
121
 * than specified time.
122
 *
123
 * @param {Thenable.<*>} promise
124
 * @param {int} time Throttle time in milliseconds
125
 * @return {Thenable.<*>}
126
 */
127
function throttle (promise, time) {
128
  var delayed = delay(time)
129
  var target = delayed
130
    .then(function () {
131
      return promise
132
    })
133
  target.cancel = function (silent) {
134
    delayed.cancel(silent)
135
    return target
136
  }
137
  return target
138
}
139
140
module.exports = {
141
  timeout: timeout,
142
  delay: delay,
143
  throttle: throttle,
144
  TimeoutException: TimeoutException,
145
  CancellationException: CancellationException
146
}
147